package com.spark.lola.logistics.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.spark.lola.feign.LogisticsBiFeignService;
import com.spark.lola.logistics.constant.LogisticsConstant;
import com.spark.lola.logistics.mapper.CarInfoMapper;
import com.spark.lola.logistics.mapper.DriverInfoMapper;
import com.spark.lola.logistics.mapper.ExpensesInfoMapper;
import com.spark.lola.logistics.mapper.LogisticsOrderInfoMapper;
import com.spark.lola.logistics.service.IndexService;
import com.spark.lola.logistics.vo.ExpensesStatusVo;
import com.spark.lola.logistics.vo.OrderStatusVo;
import com.spark.lola.logistics.vo.StatisticsExpensesInfoVo;
import com.spark.lola.logistics.vo.StatisticsOrderInfoVo;
import com.spark.lola.statistics.dto.FindLogisticsDto;
import com.spark.lola.statistics.entity.StatisticsDriver;
import com.spark.lola.support.common.constant.CommonConstant;
import com.spark.lola.support.common.entity.ShiroUser;
import com.spark.lola.support.common.util.TimeUtil;
import com.spark.lola.support.wms.configuration.WmsProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: Zhi-peng wang
 * @date: 2020/05/19 14:00
 **/
@Service
public class IndexServiceImpl implements IndexService {

    @Autowired
    private LogisticsOrderInfoMapper logisticsOrderInfoMapper;

    @Autowired
    private ExpensesInfoMapper expensesInfoMapper;

    @Autowired
    private DriverInfoMapper driverInfoMapper;

    @Autowired
    private CarInfoMapper carInfoMapper;

    @Autowired
    private LogisticsBiFeignService logisticsBiFeignService;

    @Autowired
    private WmsProperties wmsProperties;

    @Override
    public StatisticsDriver findAllData(int findType, ShiroUser shiroUser) throws ParseException {
        // 判断是否是货运部门
        Long driverId = null;
        if (wmsProperties.getLogistics().getDutyId().get(1).equals(shiroUser.getDutyId())) {
            driverId = shiroUser.getId();
        }
        FindLogisticsDto<?> findLogisticsDto = getFindStatisticsDriverDto(driverId, findType);
        List<StatisticsDriver> statisticsLogisticsList = logisticsBiFeignService.findStatisticsDriver(findLogisticsDto);
        return countAll(statisticsLogisticsList);
    }

    @Override
    public JSONObject findHardwareData() {
        int driverNumber = driverInfoMapper.countByUsed(CommonConstant.Y);
        int carNumber = carInfoMapper.countByUsed(CommonConstant.Y);
        int otherCarNumber = logisticsOrderInfoMapper.countOtherCar();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("driverNumber", driverNumber);
        jsonObject.put("carNumber", carNumber);
        jsonObject.put("otherCarNumber", otherCarNumber);
        return jsonObject;
    }

    @Override
    public JSONObject findBiData(int findType, ShiroUser shiroUser) throws ParseException {
        // 判断是否是货运部门
        Long driverId = null;
        if (wmsProperties.getLogistics().getDutyId().get(1).equals(shiroUser.getDutyId())) {
            driverId = shiroUser.getId();
        }

        FindLogisticsDto<?> findLogisticsDto = getFindStatisticsDriverDto(driverId, findType);

        JSONObject jsonObject = new JSONObject();
        // 查询统计记录
        List<StatisticsDriver> statisticsLogisticsList = logisticsBiFeignService.findStatisticsDriver(findLogisticsDto);
        // 总统计
        StatisticsDriver allData = countAll(statisticsLogisticsList);
        // 走势图统计
        switch (findType) {
            // 全部
            case LogisticsConstant.BiFindType.ALL:
                Map<Integer, List<StatisticsDriver>> mapAll = statisticsLogisticsList.stream().collect(Collectors.groupingBy(StatisticsDriver::getCreateYear, LinkedHashMap::new, Collectors.toList()));
                List<StatisticsDriver> chartAll = new ArrayList<>();
                for (Integer createYear : mapAll.keySet()) {
                    StatisticsDriver countAll = countAll(mapAll.get(createYear));
                    countAll.setCreateYear(createYear);
                    chartAll.add(countAll);
                }
                jsonObject.put("chart", chartAll);
                break;
            // 周
            case LogisticsConstant.BiFindType.WEEK:
                // 月
            case LogisticsConstant.BiFindType.MONTH:
                Map<Date, List<StatisticsDriver>> mapWeekAndMonth = statisticsLogisticsList.stream().collect(Collectors.groupingBy(StatisticsDriver::getCreateDate, LinkedHashMap::new, Collectors.toList()));
                List<StatisticsDriver> chartWeekAndMonth = new ArrayList<>();
                for (Date createDate : mapWeekAndMonth.keySet()) {
                    StatisticsDriver countAll = countAll(mapWeekAndMonth.get(createDate));
                    countAll.setCreateDate(createDate);
                    chartWeekAndMonth.add(countAll);
                }
                jsonObject.put("chart", chartWeekAndMonth);
                break;
            // 季度
            case LogisticsConstant.BiFindType.QUARTER:
                // 年
            case LogisticsConstant.BiFindType.YEAR:
                Map<Integer, List<StatisticsDriver>> mapQuarterAndYear = statisticsLogisticsList.stream().collect(Collectors.groupingBy(StatisticsDriver::getCreateMonth, LinkedHashMap::new, Collectors.toList()));
                List<StatisticsDriver> chartQuarterAndYear = new ArrayList<>();
                for (Integer createMouth : mapQuarterAndYear.keySet()) {
                    StatisticsDriver countAll = countAll(mapQuarterAndYear.get(createMouth));
                    countAll.setCreateMonth(createMouth);
                    chartQuarterAndYear.add(countAll);
                }
                jsonObject.put("chart", chartQuarterAndYear);
                break;
            default:
                return null;
        }
        jsonObject.put("all", allData);
        return jsonObject;
    }

    @Override
    public OrderStatusVo findOrderStatusData() {
        int waitShipments = logisticsOrderInfoMapper.countByStatus(LogisticsConstant.OrderStatus.WAIT_SHIPMENTS);
        int alreadyShipments = logisticsOrderInfoMapper.countByStatus(LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS);
        int alreadyReceiving = logisticsOrderInfoMapper.countByStatus(LogisticsConstant.OrderStatus.ALREADY_RECEIVING);
        int alreadyGathering = logisticsOrderInfoMapper.countByStatus(LogisticsConstant.OrderStatus.ALREADY_GATHERING);
        int alreadyComplete = logisticsOrderInfoMapper.countByStatus(LogisticsConstant.OrderStatus.ALREADY_COMPLETE);
        Map<String, Integer> map = wmsProperties.getLogistics().getExpires();
        int carLicenseNumber = carInfoMapper.countWarn(LogisticsConstant.CarWarn.CAR_LICENSE, getWarnDate(map.get("rwc")));
        int compulsoryNumber = carInfoMapper.countWarn(LogisticsConstant.CarWarn.COMPULSORY_INSURANCE, getWarnDate(map.get("compulsory")));
        int commercialNumber = carInfoMapper.countWarn(LogisticsConstant.CarWarn.COMMERCIAL_INSURANCE, getWarnDate(map.get("commercial")));
        int inspectionNumber = carInfoMapper.countWarn(LogisticsConstant.CarWarn.INSPECTION, getWarnDate(map.get("inspection")));
        return new OrderStatusVo(
                waitShipments, alreadyShipments, alreadyReceiving, alreadyGathering, alreadyComplete, carLicenseNumber,
                compulsoryNumber, commercialNumber, inspectionNumber
        );
    }

    private Date getWarnDate(int warnDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, warnDate);
        return calendar.getTime();
    }

    @Override
    public ExpensesStatusVo findExpensesStatusData() {
//        int waitLogisticsAudit = expensesInfoMapper.countByStatus(LogisticsConstant.ExpensesStatus.WAIT_LOGISTICS_AUDIT);
        int waitFinanceAudit = expensesInfoMapper.countByStatus(LogisticsConstant.ExpensesStatus.WAIT_AUDIT);
        int waitRefund = expensesInfoMapper.countByStatus(LogisticsConstant.ExpensesStatus.WAIT_REFUND);
        int alreadyComplete = expensesInfoMapper.countByStatus(LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE);
        return new ExpensesStatusVo(waitFinanceAudit, waitRefund, alreadyComplete);
    }

    private FindLogisticsDto<?> getFindStatisticsDriverDto(Long driverId, int findType) throws ParseException {
        FindLogisticsDto<?> findLogisticsDto = null;
        switch (findType) {
            // 全部
            case LogisticsConstant.BiFindType.ALL:
                findLogisticsDto = new FindLogisticsDto<>(driverId, findType, null, null);
                break;
            case LogisticsConstant.BiFindType.DAY:
                DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                findLogisticsDto = new FindLogisticsDto<>(driverId, findType, dateFormat.parse(dateFormat.format(new Date())), null);
                break;
            // 周
            case LogisticsConstant.BiFindType.WEEK:
                Date startDay = getWeek(false);
                Date endDay = getWeek(true);
                findLogisticsDto = new FindLogisticsDto<>(driverId, findType, startDay, endDay);
                break;
            // 月
            case LogisticsConstant.BiFindType.MONTH:
                int month = TimeUtil.getMonth(new Date());
                findLogisticsDto = new FindLogisticsDto<>(driverId, findType, month, null);
                break;
            // 季度
            case LogisticsConstant.BiFindType.QUARTER:
                Calendar startCalendar = Calendar.getInstance();
                startCalendar.set(Calendar.MONTH, (startCalendar.get(Calendar.MONTH) / 3) * 3);
                startCalendar.set(Calendar.DAY_OF_MONTH, 1);
                int startMonth = TimeUtil.getMonth(startCalendar.getTime());
                Calendar endCalendar = Calendar.getInstance();
                endCalendar.set(Calendar.MONTH, (startCalendar.get(Calendar.MONTH) / 3) * 3 + 2);
                endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
                int endMonth = TimeUtil.getMonth(endCalendar.getTime());
                findLogisticsDto = new FindLogisticsDto<>(driverId, findType, startMonth, endMonth);
                break;
            // 年
            case LogisticsConstant.BiFindType.YEAR:
                int year = TimeUtil.getYear(new Date());
                findLogisticsDto = new FindLogisticsDto<>(driverId, findType, year, null);
                break;
            default:
                break;
        }
        return findLogisticsDto;
    }

    private Date getWeek(boolean isEnd) throws ParseException {
        // 计算时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.DAY_OF_WEEK, 2);
        if (isEnd) {
            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + 6);
        }
        return simpleDateFormat.parse(simpleDateFormat.format(calendar.getTime()));
    }

    private StatisticsDriver findTodayData(Long driverId) throws ParseException {
        // 计算时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        Date startDate = calendar.getTime();
        DateFormat dateFormat_start = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        DateFormat dateFormat_end = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
        // 开始时间
        Date startTime = simpleDateFormat.parse(dateFormat_start.format(startDate));
        // 结束时间
        Date endTime = simpleDateFormat.parse(dateFormat_end.format(startDate));
        // 获取指定时间段指定状态的货运单集合
        StatisticsDriver statisticsDriver = new StatisticsDriver(startTime);
        List<StatisticsOrderInfoVo> statisticsOrderInfoVoList = logisticsOrderInfoMapper.findStatistics(LogisticsConstant.OrderStatus.ALREADY_GATHERING, startTime, endTime, driverId, null);
        if (CollectionUtils.isEmpty(statisticsOrderInfoVoList)) {
            return statisticsDriver;
        }
        BigDecimal transportTotal = new BigDecimal(0);
        // 总费用
        BigDecimal actualAmount = new BigDecimal(0);
        // 已结算费用
        BigDecimal settlementMoney = new BigDecimal(0);
        for (StatisticsOrderInfoVo item : statisticsOrderInfoVoList) {
            transportTotal = transportTotal.add(item.getTransportTotal());
            actualAmount = actualAmount.add(item.getActualAmount());
            if (item.getStatus() == LogisticsConstant.OrderStatus.ALREADY_COMPLETE) {
                settlementMoney = settlementMoney.add(item.getActualAmount());
            }
        }
        statisticsDriver.setLogisticsNumber(statisticsOrderInfoVoList.size());
        statisticsDriver.setLogisticsTotalWeight(transportTotal);
        statisticsDriver.setLogisticsMoney(actualAmount);
        statisticsDriver.setLogisticsSettlementMoney(settlementMoney);
        statisticsDriver.setLogisticsNotSettlementMoney(actualAmount.subtract(settlementMoney));
        List<StatisticsExpensesInfoVo> statisticsExpensesInfoVoList = expensesInfoMapper.findStatistics(LogisticsConstant.ExpensesStatus.WAIT_REFUND, startTime, endTime, null, null);
        if (!CollectionUtils.isEmpty(statisticsExpensesInfoVoList)) {
            int allMileage = 0;
            // 总退费用
            BigDecimal refundableFee = new BigDecimal(0);
            // 已退费用
            BigDecimal alreadyRefundableFee = new BigDecimal(0);
            for (StatisticsExpensesInfoVo item : statisticsExpensesInfoVoList) {
                allMileage += item.getNowMileage() - item.getPreMileage();
                refundableFee = refundableFee.add(item.getRefundableFee());
                if (item.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE) {
                    alreadyRefundableFee = alreadyRefundableFee.add(item.getRefundableFee());
                }
            }
            statisticsDriver.setLogisticsMileage(allMileage);
            statisticsDriver.setExpensesMoney(refundableFee);
            statisticsDriver.setExpensesSettlementMoney(alreadyRefundableFee);
            statisticsDriver.setExpensesNotSettlementMoney(refundableFee.subtract(alreadyRefundableFee));
        }
        return statisticsDriver;
    }

    private StatisticsDriver countAll(List<StatisticsDriver> statisticsDrivers) {
        Integer logisticsNumber = 0;
        BigDecimal logisticsMoney = BigDecimal.ZERO;
        BigDecimal logisticsSettlementMoney = BigDecimal.ZERO;
        BigDecimal logisticsNotSettlementMoney = BigDecimal.ZERO;
        BigDecimal expensesMoney = BigDecimal.ZERO;
        BigDecimal expensesSettlementMoney = BigDecimal.ZERO;
        BigDecimal expensesNotSettlementMoney = BigDecimal.ZERO;
        BigDecimal logisticsTotalWeight = BigDecimal.ZERO;
        Integer logisticsMileage = 0;
        for (StatisticsDriver item : statisticsDrivers) {
            logisticsNumber += item.getLogisticsNumber();
            logisticsMoney = logisticsMoney.add(item.getLogisticsMoney());
            logisticsSettlementMoney = logisticsSettlementMoney.add(item.getLogisticsSettlementMoney());
            logisticsNotSettlementMoney = logisticsNotSettlementMoney.add(item.getLogisticsNotSettlementMoney());

            expensesMoney = expensesMoney.add(item.getExpensesMoney());
            expensesSettlementMoney = expensesSettlementMoney.add(item.getExpensesSettlementMoney());
            expensesNotSettlementMoney = expensesNotSettlementMoney.add(item.getExpensesNotSettlementMoney());

            logisticsTotalWeight = logisticsTotalWeight.add(item.getLogisticsTotalWeight());
            logisticsMileage += item.getLogisticsMileage();
        }
        return new StatisticsDriver(logisticsNumber, logisticsMoney, logisticsSettlementMoney, logisticsNotSettlementMoney,
                expensesMoney, expensesSettlementMoney, expensesNotSettlementMoney, logisticsTotalWeight,
                logisticsMileage, CollectionUtils.isEmpty(statisticsDrivers) ? null : statisticsDrivers.get(0).getCreateDate());
    }

}
